/*
  Copyright (c) 2011 Arduino.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#ifndef _PINS_ARDUINO_H_
#define _PINS_ARDUINO_H_
// Include board variant
#include "variant.h"


// Arduino digital pins alias
// GPIO port (A to G) * 16 pins: 53
enum {
  D0,   D1,   D2,   D3,   D4,   D5,   D6,   D7,   D8,   D9,
  D10,  D11,  D12,  D13,  D14,  D15,  D16,  D17,  D18,  D19,
  D20,  D21,  D22,  D23,  D24,  D25,  D26,  D27,  D28,  D29,
  D30,  D31,  D32,  D33,  D34,  D35,  D36,  D37,  D38,  D39,
  D40,  D41,  D42,  D43,  D44,  D45,  D46,  D47,  D48,  D49,
  D50,  D51,  D52,  D53,  D54,  D55,  D56,  D57,  D58,  D59,
  D60,  D61,  D62,  D63,  D64,
  DMAX
};

// Arduino analog pins
// Analog pins must be contiguous to be able to loop on each value
#define MAX_ANALOG_INPUTS 6

#define AEND (NUM_ANALOG_FIRST+NUM_ANALOG_INPUTS)

#if NUM_ANALOG_INPUTS > 0
#define PIN_A0       NUM_ANALOG_FIRST
static const uint8_t A0 = PIN_A0;
#endif
#if NUM_ANALOG_INPUTS > 1
#define PIN_A1       (PIN_A0 + 1)
static const uint8_t A1 = PIN_A1;
#endif
#if NUM_ANALOG_INPUTS > 2
#define PIN_A2       (PIN_A1 + 1)
static const uint8_t A2 = PIN_A2;
#endif
#if NUM_ANALOG_INPUTS > 3
#define PIN_A3       (PIN_A2 + 1)
static const uint8_t A3 = PIN_A3;
#endif
#if NUM_ANALOG_INPUTS > 4
#define PIN_A4       (PIN_A3 + 1)
static const uint8_t A4 = PIN_A4;
#endif
#if NUM_ANALOG_INPUTS > 5
#define PIN_A5       (PIN_A4 + 1)
static const uint8_t A5 = PIN_A5;
#endif

// Default for Arduino connector compatibility
// SPI Definitions
#ifndef PIN_SPI_SS
#define PIN_SPI_SS                  10
#endif
#ifndef PIN_SPI_SS1
#define PIN_SPI_SS1                 4
#endif
#ifndef PIN_SPI_SS2
#define PIN_SPI_SS2                 7
#endif
#ifndef PIN_SPI_SS3
#define PIN_SPI_SS3                 8
#endif
#ifndef PIN_SPI_MOSI
#define PIN_SPI_MOSI                11
#endif
#ifndef PIN_SPI_MISO
#define PIN_SPI_MISO                12
#endif
#ifndef PIN_SPI_SCK
#define PIN_SPI_SCK                 13
#endif

static const uint8_t SS   = PIN_SPI_SS;
static const uint8_t SS1  = PIN_SPI_SS1;
static const uint8_t SS2  = PIN_SPI_SS2;
static const uint8_t SS3  = PIN_SPI_SS3;
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK  = PIN_SPI_SCK;

// I2C Definitions
#ifndef PIN_WIRE_SDA
#define PIN_WIRE_SDA                14
#endif
#ifndef PIN_WIRE_SCL
#define PIN_WIRE_SCL                15
#endif

static const uint8_t SDA = PIN_WIRE_SDA;
static const uint8_t SCL = PIN_WIRE_SCL;

#ifdef __cplusplus
extern "C" {
#endif

#define NOT_AN_INTERRUPT            NC // -1

// Convert a digital pin number Dxx to a PinName PX_n
// Note: Analog pin is also a digital pin.
#define digitalPinToPinName(p)      (((uint32_t)p < NUM_DIGITAL_PINS) ? digitalPin[p] : NC)
// Convert a PinName PX_n to a digital pin number
uint32_t pinNametoDigitalPin(PinName p);

// Convert an analog pin number to a digital pin number
// Used by analogRead api to have A0 == 0
#define analogInputToDigitalPin(p)  (((uint32_t)p < NUM_ANALOG_INPUTS) ? (p+A0) : p)
// Convert an analog pin number Axx to a PinName PX_n
#define analogInputToPinName(p)     (digitalPinToPinName(analogInputToDigitalPin(p)))
// All pins could manage EXTI
#define digitalPinToInterrupt(p)    (digitalPinIsValid(p) ? p : NOT_AN_INTERRUPT)

#define digitalPinHasI2C(p)         (pin_in_pinmap(digitalPinToPinName(p), PinMap_I2C_SDA) ||\
                                     pin_in_pinmap(digitalPinToPinName(p), PinMap_I2C_SCL))
#define digitalPinHasPWM(p)         (pin_in_pinmap(digitalPinToPinName(p), PinMap_PWM))
#define digitalPinHasSerial(p)      (pin_in_pinmap(digitalPinToPinName(p), PinMap_UART_RX) ||\
                                     pin_in_pinmap(digitalPinToPinName(p), PinMap_UART_TX))
#define digitalPinHasSPI(p)         (pin_in_pinmap(digitalPinToPinName(p), PinMap_SPI_MOSI) ||\
                                     pin_in_pinmap(digitalPinToPinName(p), PinMap_SPI_MISO) ||\
                                     pin_in_pinmap(digitalPinToPinName(p), PinMap_SPI_SCLK) ||\
                                     pin_in_pinmap(digitalPinToPinName(p), PinMap_SPI_SSEL))


#define digitalPinToPort(p)         (get_GPIO_Port(STM_PORT(digitalPinToPinName(p))))
#define digitalPinToBitMask(p)      (STM_GPIO_PIN(digitalPinToPinName(p)))

#define analogInPinToBit(p)         (STM_PIN(digitalPinToPinName(p)))
#define portOutputRegister(P)       (&(P->ODR))
#define portInputRegister(P)        (&(P->IDR))

#define portConfigRegister(P)       (portModeRegister(P))


#define digitalPinIsValid(p)        (digitalPinToPinName(p) != NC)

// As some pin could be duplicated in digitalPin[]
// return first occurence of linked PinName (PYx)
#define digitalPinFirstOccurence(p) (pinNametoDigitalPin(digitalPinToPinName(p)))

// Specific for Firmata. As some pins could be duplicated,
// ensure 'p' is not one of the serial pins
#if defined(PIN_SERIAL_RX) && defined(PIN_SERIAL_TX)
#define pinIsSerial(p)              ((digitalPinFirstOccurence(p) == PIN_SERIAL_RX) ||\
                                     (digitalPinFirstOccurence(p) == PIN_SERIAL_TX))
#endif
#ifdef __cplusplus
}
#endif

// Default Definitions, could be redefined in variant.h
#ifndef ADC_RESOLUTION
#define ADC_RESOLUTION              12
#endif
#ifndef DACC_RESOLUTION
#define DACC_RESOLUTION             12
#endif
#ifndef PWM_RESOLUTION
#define PWM_RESOLUTION              8
#endif
#ifndef PWM_FREQUENCY
#define PWM_FREQUENCY               1000
#endif
#ifndef PWM_MAX_DUTY_CYCLE
#define PWM_MAX_DUTY_CYCLE          255
#endif

#endif /*_PINS_ARDUINO_H_*/
